#include "compute_hash.h"

int generate_salt(unsigned char *salt, size_t salt_len) {
    if (salt_len != SALT_LENGTH) {
        fprintf(stderr, "错误：盐值长度不正确\n");
        return -1;
    }
    if (RAND_bytes(salt, salt_len) != 1) {
        fprintf(stderr, "错误：生成随机盐值失败 - %s\n", strerror(errno));
        return -1;
    }
    return 0;
}

void salt_to_hex(const unsigned char *salt, size_t salt_len, char *hex_salt, size_t hex_salt_len) {
    for (size_t i = 0; i < salt_len; i++) {
        sprintf(&hex_salt[i * 2], "%02x", salt[i]);
    }
    hex_salt[salt_len * 2] = '\0';
}

int calculate_sha256(const char *data, size_t data_len, unsigned char *hash) {
    SHA256_CTX sha256;
    if (!SHA256_Init(&sha256)) {
        fprintf(stderr, "错误：SHA256 初始化失败\n");
        return -1;
    }
    if (!SHA256_Update(&sha256, data, data_len)) {
        fprintf(stderr, "错误：SHA256 更新失败\n");
        return -1;
    }
    if (!SHA256_Final(hash, &sha256)) {
        fprintf(stderr, "错误：SHA256 完成失败\n");
        return -1;
    }
    return 0;
}

void hash_to_hex(const unsigned char *hash, size_t hash_len, char *hex_hash, size_t hex_hash_len) {
    for (size_t i = 0; i < hash_len; i++) {
        sprintf(&hex_hash[i * 2], "%02x", hash[i]);
    }
    hex_hash[hash_len * 2] = '\0';
}

/**
 * @brief 对输入的密码进行加密处理，结合随机盐值和 SHA-256 哈希算法。
 * 
 * 该函数会生成一个随机盐值，将其与输入密码拼接，然后计算拼接后字符串的 SHA-256 哈希值。
 * 最后将盐值和哈希值转换为十六进制字符串输出。
 * 
 * @param password 输入的原始密码，以 null 结尾的字符串。
 * @param hex_salt_out 用于存储十六进制格式盐值的缓冲区。
 * @param hex_salt_out_len 存储十六进制盐值缓冲区的长度。
 * @param hex_hash_out 用于存储十六进制格式哈希值的缓冲区。
 * @param hex_hash_out_len 存储十六进制哈希值缓冲区的长度。
 * @return 若所有操作成功，返回 0；若任意步骤失败，返回 -1。
 */
int encrypt_password(const char *password, char *hex_salt_out, size_t hex_salt_out_len, char *hex_hash_out, size_t hex_hash_out_len) {
    // 定义一个数组用于存储生成的二进制盐值，长度为预定义的 SALT_LENGTH
    unsigned char salt[SALT_LENGTH];
    // 定义一个数组用于存储计算得到的 SHA-256 哈希值，长度为 SHA-256 摘要长度
    unsigned char hash[SHA256_DIGEST_LENGTH];
    // 定义一个数组用于存储拼接后的密码和盐值字符串，预留足够的空间
    char salted_password[MAX_PASSWORD_LENGTH + SALT_LENGTH + 1];

    // 调用 generate_salt 函数生成随机盐值
    // 若生成失败，函数返回 -1 表示错误
    if (generate_salt(salt, sizeof(salt)) != 0) {
        return -1;
    }
    // 1. 获取实际密码长度
    size_t password_len = strlen(password);
    if (password_len > MAX_PASSWORD_LENGTH) {
        password_len = MAX_PASSWORD_LENGTH; // 确保长度不超过最大值
    }
    // 调用 salt_to_hex 函数将二进制盐值转换为十六进制字符串
    // 结果存储在 hex_salt_out 缓冲区中
    salt_to_hex(salt, sizeof(salt), hex_salt_out, hex_salt_out_len);
    
    // 2. 拼接密码和盐值
    memcpy(salted_password, password, password_len);
    memcpy(salted_password + password_len, salt, SALT_LENGTH);
    // // 将输入的密码复制到 salted_password 数组中
    // // 使用 strncpy 确保不会超出最大密码长度
    // memcpy(salted_password, password, strlen(password));
    // // strncpy(salted_password, password, MAX_PASSWORD_LENGTH);
    // // 在复制的密码末尾添加字符串结束符
    // salted_password[MAX_PASSWORD_LENGTH] = '\0';

    // // 将生成的二进制盐值追加到 salted_password 数组中
    // memcpy(salted_password + strlen(password), salt, SALT_LENGTH);
    // // strncat(salted_password, (char *)salt, SALT_LENGTH);
    // // 在拼接后的字符串末尾添加字符串结束符
    // salted_password[MAX_PASSWORD_LENGTH + SALT_LENGTH] = '\0';
    
    // 3. 计算要哈希的总长度
    size_t data_to_hash_len = password_len + SALT_LENGTH;
    // 调用 calculate_sha256 函数计算拼接后字符串的 SHA-256 哈希值
    // 若计算失败，函数返回 -1 表示错误
    if (calculate_sha256(salted_password, data_to_hash_len, hash) != 0) {
        return -1;
    }

    // 调用 hash_to_hex 函数将二进制哈希值转换为十六进制字符串
    // 结果存储在 hex_hash_out 缓冲区中
    hash_to_hex(hash, sizeof(hash), hex_hash_out, hex_hash_out_len);

    // 所有操作成功，返回 0 表示正常完成
    return 0;
}

int verify_password(const char *input_password, const char *stored_hex_salt, const char *stored_hex_hash) {
    unsigned char salt[SALT_LENGTH];
    unsigned char calculated_hash[SHA256_DIGEST_LENGTH];
    char salted_password[MAX_PASSWORD_LENGTH + SALT_LENGTH + 1];
    char calculated_hex_hash[HEX_SHA256_LENGTH];

    if (strlen(stored_hex_salt) != SALT_LENGTH * 2) {
        fprintf(stderr, "错误：存储的盐值格式不正确\n");
        LOG_INFO("stored_hex_salt type is wrong, stored_hex_salt = %s\n", stored_hex_salt);
        return -1;
    }
    for (size_t i = 0; i < SALT_LENGTH; i++) {
        sscanf(&stored_hex_salt[i * 2], "%2hhxx", &salt[i]);
        LOG_INFO("salt[%d] = %x\n", i, salt[i]);
    }
    // 1. 获取实际密码长度 (与 encrypt_password 逻辑一致)
    size_t password_len = strlen(input_password);
    if (password_len > MAX_PASSWORD_LENGTH) {
        password_len = MAX_PASSWORD_LENGTH;
    }

    // 2. 拼接密码和盐值 (与 encrypt_password 逻辑一致)
    memcpy(salted_password, input_password, password_len);
    LOG_INFO("salted_password = %s\n", salted_password);
    memcpy(salted_password + password_len, salt, SALT_LENGTH);
    LOG_INFO("salted_password = %s\n", salted_password);
    // // strncpy(salted_password, input_password, MAX_PASSWORD_LENGTH);
    // memcpy(salted_password, input_password, strlen(input_password));
    // salted_password[MAX_PASSWORD_LENGTH] = '\0';
    // // strncat(salted_password, (char *)salt, SALT_LENGTH);
    // memcpy(salted_password + strlen(input_password), salt, SALT_LENGTH);
    // salted_password[MAX_PASSWORD_LENGTH + SALT_LENGTH] = '\0';

    // 3. 计算要哈希的总长度 (与 encrypt_password 逻辑一致)
    size_t data_to_hash_len = password_len + SALT_LENGTH;
    if (calculate_sha256(salted_password, data_to_hash_len, calculated_hash) != 0) {
        return -1;
    }

    hash_to_hex(calculated_hash, sizeof(calculated_hash), calculated_hex_hash, sizeof(calculated_hex_hash));
    calculated_hex_hash[HEX_SHA256_LENGTH] = '\0';
    LOG_INFO("calculated_hex_hash = %s\n", calculated_hex_hash);

    if (strcmp(calculated_hex_hash, stored_hex_hash) == 0) {
        return 1;
    } else {
        return 0;
    }
}